#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"
#include "Thread.hpp"
#include "LockGuard.hpp"

namespace nt_client
{
    class UdpClient
    {
    public:
        // 构造
        UdpClient(const std::string& ip, uint16_t port)
            :server_ip_(ip), server_port_(port)
        {
            // 创建线程
            recv_ = new Thread(1, std::bind(&UdpClient::RecvMessage, this));
            send_ = new Thread(2, std::bind(&UdpClient::SendMessage, this));
        }

        // 析构
        ~UdpClient() 
        {
            // 等待线程退出
            recv_->join();
            send_->join();

            delete (recv_);
            delete (send_);
        } 

        // 启动客户端
        void StartClient() 
        {
            // 1.创建套接字
            sock_ = socket(AF_INET, SOCK_DGRAM, 0);

            if(sock_ == -1)
            {
                std::cout << "Create Socket Fail: " << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }

            std::cout << "Create Success Socket: " << sock_ << std::endl;

            // 2.构建服务器的 sockaddr_in 结构体信息
            bzero(&svr_, sizeof(svr_));
            svr_.sin_family = AF_INET; // 设置为网络通信（PF_INET 也行）
            svr_.sin_addr.s_addr = inet_addr(server_ip_.c_str()); // 绑定服务器IP地址
            svr_.sin_port = htons(server_port_); // 绑定服务器端口号

            // 启动线程
            recv_->run();
            send_->run();
        }

        // 发送消息
        void RecvMessage() 
        {
            while(true)
            {
                // 发送消息
                std::string msg;
                std::cout << "Input Message# ";
                std::getline(std::cin, msg);

                ssize_t n = sendto(sock_, msg.c_str(), msg.size(), 0, (const struct sockaddr*)&svr_, sizeof(svr_));

                if(n == -1)
                {
                    std::cout << "Send Message Fail: " << strerror(errno) << std::endl;
                    continue; // 重新输入消息并发送
                }
            }
        }

        // 接收消息
        void SendMessage()
        {
            char buff[1024];
            while(true)
            {
                // 2.接收消息
                socklen_t len = sizeof(svr_); // 创建一个变量，因为接下来的参数需要传左值
                ssize_t n = recvfrom(sock_, buff, sizeof(buff) - 1, 0, (struct sockaddr*)&svr_, &len);

                if(n > 0)
                    buff[n] = '\0';
                else
                    continue;

                std::cout << "Client get message " << buff << std::endl;
            }
        }

    private:
        std::string server_ip_; // 服务器IP地址
        uint16_t server_port_; // 服务器端口号
        int sock_;
        struct sockaddr_in svr_; // 服务器的sockadder_in结构体信息
        Thread* recv_; // 发送消息
        Thread* send_; // 接收消息
    };
}
